---
title: "Inputs"
---

Server actions in `zsa` can accept validated inputs using Zod schemas. This allows you to ensure that the data passed to your server action matches the expected format.

You can install `zod` with `npm i zod` or `yarn add zod`.

## Basic Input Schemas

The most basic way to define an input schema is by passing a Zod schema to the `input` method when creating a server action:

```typescript
import { createServerAction } from 'zsa';
import { z } from 'zod';

export const myAction = createServerAction()
  .input(
    z.object({
      name: z.string(),
      age: z.number().min(18),
    })
  )
  .handler(async ({ input }) => {
    // input is validated to match the schema
    console.log(input.name, input.age); 
  });
```

If the input passed to `myAction` does not match the defined schema (e.g. `name` is missing or `age` is less than 18), a `ZSAError` will be thrown with code `INPUT_PARSE_ERROR`.

## Dynamic Input Schemas

<Warning>
Although useful in some cases, this should be avoided by default since creating a schema for every request is going to be much more expensive than reusing an existing one.
</Warning>

For more advanced use cases, you can define the input schema using a function that returns a Zod schema. This allows you to dynamically generate the schema based on data available when the action is invoked, such as data from the request or context from procedures.

The input schema function receives an object with the following properties:
- `ctx`: The context object generated by any procedures
- `previousSchema`: The previous schema of the action if there exists a parent procedure
- `request`: The Next.js request object if the action is run through an OpenAPI route handler
- `responseMeta`: The response metadata object if the action is run through an OpenAPI route handler
- `previousState`: The previous state of the action if the action is run through `useActionState`

Here's an example of using a function to dynamically generate an input schema:

```typescript
import { createServerAction } from 'zsa';
import { z } from 'zod';

export const myAction = createServerAction()  
  .input(({ request, ctx, responseMeta, previousState, previousSchema }) => 
    z.object({
      // Require age to be greater than value in request header
      age: z.number().min(parseInt(request.headers.get('min-age') ?? '0')),
      // Only require email if user is not logged in
      email: !ctx.user ? z.string().email() : z.string().email().optional(),
    })
  )
  .handler(async ({ input, ctx }) => {
    // input is generated based on request data and procedure context  
  });
```

Some potential use cases for dynamic input schemas:

- Changing required fields based on user roles/permissions
- Adding extra validation based on feature flags or environment variables 
- Modifying numeric limits based on user subscription level

By defining input schemas as functions, you can create more flexible and context-aware server action inputs. The schema will be evaluated with the latest request data and procedure context each time the action is invoked.